#pragma once

#include <iostream>
#include <string>
#include <functional>

#include <unistd.h>
#include <pthread.h>


#include "Sock.hpp"
#include "Protocol.hpp"

namespace my_ser
{
    using namespace TCP;
    using namespace protocol;


    class Server;
    class ThreadData // v3线程创建 线程函数数据
    {
    public:
        ThreadData(std::string ip, uint16_t port, int sockfd, Server *ser)
            : _ip(ip), _port(port), _sockfd(sockfd), _ser(ser)
        {
        }

        std::string _ip;
        uint16_t _port;
        int _sockfd;
        Server *_ser;
    };


    class Server
    {
        using func_t = std::function<Response(const Request&)>; //业务逻辑函数
    public:
        Server(func_t func,uint16_t port)
            :_func(func)
            ,ss(port)
        {}

        void InitServer()
        {
            ss.Socket();
            ss.Bind();
            ss.Listen();
        }

        void Start()
        {
            while(true)
            {
                std::string client_ip;
                uint16_t client_port;
                int client_sock = ss.Accept(&client_ip,&client_port);
                while(client_sock < 0)
                {
                    std::cout<<"accept error!"<<std::endl;
                    continue;
                }
                std::cout<<"client accept!"<<std::endl;

                ThreadData* t = new ThreadData(client_ip,client_port,client_sock,this);
                pthread_t tid;
                pthread_create(&tid,nullptr,ThreadFunc,(void*)t);
            }
        }

        // v3-线程 执行函数
         static void *ThreadFunc(void *args)
         {
             pthread_detach(pthread_self()); // 线程分离
             ThreadData *td = static_cast<ThreadData*>(args);
             td->_ser->ServiceIO(td->_ip,td->_port,td->_sockfd);
             delete td;
             return nullptr;
         }

        void ServiceIO(const std::string& client_ip,const uint16_t& client_port,const int& client_sockfd)
        {
            std::string inbuffer; //写入缓冲区 保存每次读取的内容 直到读取一个完整报文才被处理
            while(true)
            {
                std::string package; //读取的报文
                int n = ReadPackage(client_sockfd,inbuffer,&package); //注意 返回的是有效载荷的长度
                if(n <= 0) break; //如果n<0则异常 直接退出

                //到这里表示报文读取完整 开始处理报文
                //1.提取内容(有效载荷)
                package = RemoveHeader(package,n);

                
                //2.将读取到的有效载荷 封装成为请求包
                Request req;
                if(!req.Deserialize(package)) continue; //如果失败则重新读取
                req.Print();

                //3.通过业务逻辑计算形成响应包(计算结果+错误码)
                Response resp = _func(req);
                resp.Print();

                //4.通过响应包数据进行序列化
                std::string send_string;
                if(!resp.Serialize(&send_string)) continue; //如果失败则重新读取
                std::cout<<send_string<<std::endl;

                //5.添加报头
                send_string = AddHeader(send_string);
                std::cout<<send_string<<std::endl;


                //6.发送数据
                send(client_sockfd, send_string.c_str(), send_string.size(), 0);

            }
            close(client_sockfd);
            std::cout<<"client quit!"<<std::endl;
        }


    private:
        SockServer ss;
        func_t _func;
    };
}